/*
 * OVERVIEW:
 * This is a fragment, that represents a single detail about an instance of an agent
 * and permits operations with this agents.
 * Fragment is independent of hosting activities because it ensures that each activity
 * to host AgentFragment must implement its Callback interface.
 */

package sk.stuba.fei.ut.snmpmanager;

import java.util.UUID;

import org.snmp4j.mp.SnmpConstants;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.NavUtils;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

public class AgentFragment extends Fragment
{
	public static final String EXTRA_AGENT_ID = "sk.stuba.fei.ut.snmpmanager.agent_id";
	private static final String TAG = "AgentFragment";
	
	private Agent mAgent;
	private Callbacks mCallbacks;
	private ActionMode.Callback mActionModeCallback;
	private ActionMode mActionMode;
	private EditText mTitleField;
	private EditText mIpv4Field;
	private EditText mMACField;
	private EditText mPortField;
	private EditText mCommunityField;
	private EditText mWoLPortField;
	private EditText mPollIntervalField;
	private EditText mDetailField;
	private CheckBox mPoolingCheckBox;
	private CheckBox mTrapCheckBox;
	private Spinner mGetSpinner;
	private Spinner mVersionSpinner;
	private Button mGetButton;
	private Button mWakeButton;
	private Button mPollButton;
	private Button mStopPollButton;
	private String mSelectedOID;
	private String mSelectedOIDMeaning;

	// Interface for hosting activities.
	public interface Callbacks
	{
		void onAgentUpdated( Agent agent );
	}

	/*
	 * newInstance method is "constructor" for this Fragment, unique internal
	 * agent ID is required to setup this Fragment
	 */
	public static AgentFragment newInstance( UUID agentID )
	{
		Bundle arguments = new Bundle();
		arguments.putSerializable( EXTRA_AGENT_ID, agentID );
		AgentFragment fragment = new AgentFragment();
		fragment.setArguments( arguments );
		return fragment;
	}

	/*
	 * #### FRAGMENT LIFE-CYCLE METHODS ####
	 */
	@Override
	public void onAttach( Activity activity )
	{
		super.onAttach( activity );
		// casting to ensure hosting activity is implementing
		// required interface
		try
		{
			mCallbacks = ( Callbacks ) activity;
		}
		catch ( ClassCastException e )
		{
			throw new ClassCastException( activity.toString()
					+ " must implement Callbacks interface" );
		}

	}

	@Override
	public void onDetach()
	{
		super.onDetach();
		mCallbacks = null;
	}

	@Override
	public void onCreate( Bundle savedInstanceState )
	{
		super.onCreate( savedInstanceState );
		setHasOptionsMenu( true );

		UUID agentID = ( UUID ) getArguments().getSerializable( EXTRA_AGENT_ID );
		// get Agent by unique ID passed to the fragment
		mAgent = AgentManager.get( getActivity() ).getAgent( agentID );
		initActionModeCallbacks();
	}

	@Override
	public View onCreateView( LayoutInflater inflater, ViewGroup parent,
			Bundle savedInstanceState )
	{
		View view = inflater.inflate( R.layout.fragment_agent, parent, false );
		// enable icon to serve as back button
		getActivity().getActionBar().setDisplayHomeAsUpEnabled( true );

		// TODO: setup all the views that we need to manipulate with their
		// listeners
		TextView settings = ( TextView ) view
				.findViewById( R.id.agent_settings_textView );
		settings.requestFocus();

		mTitleField = ( EditText ) view.findViewById( R.id.agent_name_editText );
		if ( mAgent.getTitle() != null )
		{
			mTitleField.setText( mAgent.getTitle() );
		}
		mTitleField.addTextChangedListener( new TextWatcher()
		{
			@Override
			public void onTextChanged( CharSequence seq, int arg1, int arg2,
					int arg3 )
			{
				mAgent.setTitle( seq.toString() );
				mCallbacks.onAgentUpdated( mAgent );
				getActivity().setTitle( mAgent.getTitle() );
			}

			@Override
			public void beforeTextChanged( CharSequence arg0, int arg1,
					int arg2, int arg3 )
			{
			}

			@Override
			public void afterTextChanged( Editable arg0 )
			{
			}
		} );

		mMACField = ( EditText ) view.findViewById( R.id.agent_MAC_editText );
		if ( mAgent.getMACAddress() != null )
		{
			mMACField.setText( mAgent.getMACAddress() );
		}
		mMACField.addTextChangedListener( new TextWatcher()
		{
			@Override
			public void onTextChanged( CharSequence s, int start, int before,
					int count )
			{
				mAgent.setMACAddress( s.toString() );
				mCallbacks.onAgentUpdated( mAgent );
			}

			@Override
			public void beforeTextChanged( CharSequence s, int start,
					int count, int after )
			{
			}

			@Override
			public void afterTextChanged( Editable s )
			{
			}
		} );

		mIpv4Field = ( EditText ) view.findViewById( R.id.agent_ip_editText );
		if ( mAgent.getIpv4Address() != null )
		{
			mIpv4Field.setText( mAgent.getIpv4Address() );
		}
		mIpv4Field.addTextChangedListener( new TextWatcher()
		{
			@Override
			public void onTextChanged( CharSequence s, int start, int before,
					int count )
			{
				mAgent.setIpv4Address( s.toString() );
				mCallbacks.onAgentUpdated( mAgent );
			}

			@Override
			public void beforeTextChanged( CharSequence s, int start,
					int count, int after )
			{
			}

			@Override
			public void afterTextChanged( Editable s )
			{
			}
		} );

		mPortField = ( EditText ) view.findViewById( R.id.agent_port_editText );
		if ( mAgent.getPort() != null )
		{
			mPortField.setText( mAgent.getPort() );
		}
		mPortField.addTextChangedListener( new TextWatcher()
		{

			@Override
			public void onTextChanged( CharSequence arg0, int arg1, int arg2,
					int arg3 )
			{
				mAgent.setPort( arg0.toString() );
				mCallbacks.onAgentUpdated( mAgent );
			}

			@Override
			public void beforeTextChanged( CharSequence arg0, int arg1,
					int arg2, int arg3 )
			{
			}

			@Override
			public void afterTextChanged( Editable arg0 )
			{
			}
		} );

		mCommunityField = ( EditText ) view
				.findViewById( R.id.agent_snmp_editText );
		if ( mAgent.getCommunity() != null )
		{
			mCommunityField.setText( mAgent.getCommunity() );
		}
		mCommunityField.addTextChangedListener( new TextWatcher()
		{
			@Override
			public void onTextChanged( CharSequence s, int start, int before,
					int count )
			{
				mAgent.setCommunity( s.toString() );
				mCallbacks.onAgentUpdated( mAgent );
			}

			@Override
			public void beforeTextChanged( CharSequence s, int start,
					int count, int after )
			{
			}

			@Override
			public void afterTextChanged( Editable s )
			{
			}
		} );

		mVersionSpinner = ( Spinner ) view
				.findViewById( R.id.agent_version_spinner );
		ArrayAdapter<CharSequence> versionAdapter = ArrayAdapter
				.createFromResource( getActivity(), R.array.snmpVersions,
						android.R.layout.simple_spinner_item );
		versionAdapter
				.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item );
		mVersionSpinner.setAdapter( versionAdapter );
		if ( mAgent.getVersion() == SnmpConstants.version2c )
		{
			mVersionSpinner.setSelection( 1 );
		}
//		if ( mAgent.getVersion() == SnmpConstants.version3 )
//		{
//			mVersionSpinner.setSelection( 2 );
//		}
		mVersionSpinner.setOnItemSelectedListener( new OnItemSelectedListener()
		{
			public void onItemSelected( AdapterView<?> arg0, View arg1,
					int arg2, long arg3 )
			{
				int index = arg0.getSelectedItemPosition();
				if ( index == 0 )
				{
					mAgent.setVersion( SnmpConstants.version1 );
					mCallbacks.onAgentUpdated( mAgent );
				}
				else if ( index == 1 )
				{
					mAgent.setVersion( SnmpConstants.version2c );
					mCallbacks.onAgentUpdated( mAgent );
				}
//				else if ( index == 2 )
//				{
//					Log.i( TAG, "Selected version is " + index );
//					mAgent.setVersion( SnmpConstants.version3 );
//					mCallbacks.onAgentUpdated( mAgent );
//				}

			}

			public void onNothingSelected( AdapterView<?> arg0 )
			{

			}
		} );

		mTrapCheckBox = ( CheckBox ) view
				.findViewById( R.id.agent_trapsEnabledCheckBox );
		mTrapCheckBox.setChecked( mAgent.isCatchingTraps() );
		mTrapCheckBox
				.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener()
				{
					@Override
					public void onCheckedChanged( CompoundButton buttonView,
							boolean isChecked )
					{
						mAgent.setCatchingTraps( isChecked );
						mCallbacks.onAgentUpdated( mAgent );
					}
				} );

		mWoLPortField = ( EditText ) view
				.findViewById( R.id.agent_WoL_editText );
		if ( mAgent.getWoLport() != null )
		{
			mWoLPortField.setText( mAgent.getWoLport() );
		}
		mWoLPortField.addTextChangedListener( new TextWatcher()
		{
			@Override
			public void onTextChanged( CharSequence s, int start, int before,
					int count )
			{
				mAgent.setWoLport( s.toString() );
				mCallbacks.onAgentUpdated( mAgent );
			}

			@Override
			public void beforeTextChanged( CharSequence s, int start,
					int count, int after )
			{
			}

			@Override
			public void afterTextChanged( Editable s )
			{
			}
		} );

		mPoolingCheckBox = ( CheckBox ) view
				.findViewById( R.id.agent_poolingEnabledCheckBox );
		mPoolingCheckBox.setChecked( mAgent.isPolled() );
		mPoolingCheckBox
				.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener()
				{
					@Override
					public void onCheckedChanged( CompoundButton buttonView,
							boolean isChecked )
					{
						mAgent.setPolled( isChecked );
						mCallbacks.onAgentUpdated( mAgent );
					}
				} );

		mPollIntervalField = ( EditText ) view
				.findViewById( R.id.agent_pollInterval_editText );
		if ( mAgent.getPollingInterval() != null )
		{
			mPollIntervalField.setText( mAgent.getPollingInterval() );
		}
		mPollIntervalField.addTextChangedListener( new TextWatcher()
		{
			@Override
			public void onTextChanged( CharSequence s, int start, int before,
					int count )
			{
				mAgent.setPollingInterval( s.toString() );
				mCallbacks.onAgentUpdated( mAgent );
			}

			@Override
			public void beforeTextChanged( CharSequence s, int start,
					int count, int after )
			{
			}

			@Override
			public void afterTextChanged( Editable s )
			{
			}
		} );

		mGetSpinner = ( Spinner ) view.findViewById( R.id.agent_GET_spinner );
		ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
				getActivity(), R.array.OID_meanings,
				android.R.layout.simple_spinner_item );
		adapter.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item );
		mGetSpinner.setAdapter( adapter );
		mGetSpinner.setOnItemSelectedListener( new OnItemSelectedListener()
		{
			public void onItemSelected( AdapterView<?> arg0, View arg1,
					int arg2, long arg3 )
			{
				int index = arg0.getSelectedItemPosition();
				String[] array = getResources().getStringArray(
						R.array.OID_array );
				mSelectedOID = array[index];
				array = getResources().getStringArray( R.array.OID_meanings );
				mSelectedOIDMeaning = array[index];
			}

			public void onNothingSelected( AdapterView<?> arg0 )
			{

			}
		} );

		mGetButton = ( Button ) view.findViewById( R.id.agent_GET_Button );
		mGetButton.setOnClickListener( new OnClickListener()
		{
			@Override
			public void onClick( View arg0 )
			{
				if ( mSelectedOID == null )
				{
					Toast.makeText( getActivity(),
							R.string.agentFragment_selectGET,
							Toast.LENGTH_LONG ).show();
				}
				else
				{
					new SendGetRequest().execute();
				}
			}
		} );

		mWakeButton = ( Button ) view.findViewById( R.id.agent_WoL_Button );
		mWakeButton.setOnClickListener( new OnClickListener()
		{
			@Override
			public void onClick( View arg0 )
			{
				Intent WoL = new Intent( getActivity(), WakeOnLan.class );
				WoL.putExtra( "IPadresa", mAgent.getIpv4Address() );
				WoL.putExtra( "Port", mAgent.getWoLport() );
				WoL.putExtra( "MACadresa", mAgent.getMACAddress() );
				getActivity().startService( WoL );
			}
		} );

		mPollButton = ( Button ) view
				.findViewById( R.id.agent_Start_polling_Button );
		mPollButton.setOnClickListener( new OnClickListener()
		{
			@Override
			public void onClick( View arg0 )

			{
				// if not Polled then start Polling
				if ( mAgent.isPolled() )
				{
					Intent intent = new Intent( getActivity(),
							pollingService.class );
					PendingIntent pIntent = PendingIntent.getService(
							getActivity(), 0, intent, 0 );
					AlarmManager alarm = ( AlarmManager ) getActivity()
							.getSystemService( getActivity().ALARM_SERVICE );
					// start service in specified intervals
					int interval;
					try
					{
						interval = Integer.parseInt( mAgent
								.getPollingInterval() );
						alarm.setRepeating( AlarmManager.RTC_WAKEUP,
								System.currentTimeMillis(), 1000 * interval,
								pIntent );
					}
					catch ( NumberFormatException e )
					{
						Toast.makeText(
								getActivity(),
								R.string.agentFragment_specifyInterval,
								Toast.LENGTH_SHORT ).show();
					}

				}
				else
				{
					Toast.makeText( getActivity(),
							R.string.agentFragment_notSetForPolling, Toast.LENGTH_SHORT )
							.show();
				}

			}
		} );

		mStopPollButton = ( Button ) view
				.findViewById( R.id.agent_Stop_polling_Button );
		mStopPollButton.setOnClickListener( new OnClickListener()
		{

			@Override
			public void onClick( View arg0 )

			{ // turn OFF polling
				Intent intent = new Intent( getActivity(), pollingService.class );
				PendingIntent pIntent = PendingIntent.getService(
						getActivity(), 0, intent, 0 );
				AlarmManager alarm = ( AlarmManager ) getActivity()
						.getSystemService( getActivity().ALARM_SERVICE );
				alarm.cancel( pIntent );
			}
		} );

		mDetailField = ( EditText ) view
				.findViewById( R.id.agent_details_editText );
		if ( mAgent.getDetail() != null )
		{
			mDetailField.setText( mAgent.getDetail() );
		}
		mDetailField.addTextChangedListener( new TextWatcher()
		{

			@Override
			public void onTextChanged( CharSequence s, int start, int before,
					int count )
			{
				mAgent.setDetail( s.toString() );
				mCallbacks.onAgentUpdated( mAgent );
			}

			@Override
			public void beforeTextChanged( CharSequence s, int start,
					int count, int after )
			{
			}

			@Override
			public void afterTextChanged( Editable s )
			{
			}
		} );

		// TODO: register callback methods for context menu
		// @see ActionMode.Callback()

		view.setOnLongClickListener( new View.OnLongClickListener()
		{

			@Override
			public boolean onLongClick( View v )
			{
				if ( mActionMode != null ) return false;

				mActionMode = getActivity().startActionMode(
						mActionModeCallback );
				v.setSelected( true );
				return true;

			}
		} );

		return view;

	}

	protected AlarmManager getSystemService( String alarm_SERVICE )
	{
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onPause()
	{
		super.onPause();
		AgentManager.get( getActivity() ).saveAgents();
	}

	@Override
	public void onCreateOptionsMenu( Menu menu, MenuInflater inflater )
	{
		super.onCreateOptionsMenu( menu, inflater );
		inflater.inflate( R.menu.fragment_agent, menu );
	}

	/*
	 * #### DATA EXCHANGE AND RETRIEVAL ####
	 */
	@Override
	public void onActivityResult( int requestCode, int resultCode, Intent data )
	{
		if ( resultCode != Activity.RESULT_OK ) return;

	}

	/*
	 * #### ACTION BAR ####
	 */
	@Override
	public boolean onOptionsItemSelected( MenuItem item )
	{
		switch ( item.getItemId() )
		{
		case R.id.agent_menu_save:
			AgentManager.get( getActivity() ).saveAgents();
			Toast.makeText( getActivity(), R.string.agentFragment_saved, Toast.LENGTH_SHORT ).show();
			return true;
		case android.R.id.home:
			if ( NavUtils.getParentActivityName( getActivity() ) != null )
			{
				NavUtils.navigateUpFromSameTask( getActivity() );
			}
			return true;
		case R.id.agent_menu_delete:
			deleteAgent();
			return true;
		default:
			return super.onOptionsItemSelected( item );
		}
	}

	/*
	 * #### CONTEXTUAL ####
	 */
	public void initActionModeCallbacks()
	{
		mActionModeCallback = new ActionMode.Callback()
		{
			@Override
			public boolean onPrepareActionMode( ActionMode mode, Menu menu )
			{
				return false;
			}

			@Override
			public void onDestroyActionMode( ActionMode mode )
			{
				mActionMode = null;
			}

			@Override
			public boolean onCreateActionMode( ActionMode mode, Menu menu )
			{
				MenuInflater inflater = mode.getMenuInflater();
				inflater.inflate( R.menu.agent_item_context, menu );
				return true;
			}

			@Override
			public boolean onActionItemClicked( ActionMode mode, MenuItem item )
			{
				// TODO: what to do when each item is selected, return true if
				// something is selected, return false otherwise
				switch ( item.getItemId() )
				{
				case R.id.menu_delete_agent:
					deleteAgent();
					mode.finish();
					return true;
				default:
					return false;
				}
			}
		};
	}

	/*
	 * #### PRIVATE UTILITIES ####
	 */

	private void deleteAgent()
	{
		AgentManager agentManager = AgentManager.get( getActivity() );
		agentManager.deleteAgent( mAgent );
		if ( NavUtils.getParentActivityName( getActivity() ) != null )
		{
			NavUtils.navigateUpFromSameTask( getActivity() );
		}
	}

	// Send GET request in background thread, return response as a string
	private class SendGetRequest extends AsyncTask<Void, Void, String>
	{

		@Override
		protected String doInBackground( Void... arg0 )
		{
			try
			{
				return SNMPHelper.sendGetRequest( mAgent, mSelectedOID );
			}
			catch ( Exception e )
			{
				Log.e( TAG, "Error when sending get request\n", e );
			}
			return null;
		}

		// Show response in alert dialog, let user choose to save or not
		@Override
		protected void onPostExecute( final String response )
		{
			AlertDialog.Builder builder = new AlertDialog.Builder(
					getActivity() );
			builder.setMessage( response )
					.setTitle( R.string.agent_dialog_title )
					.setPositiveButton( R.string.agent_dialok_ok,
							new DialogInterface.OnClickListener()
							{
								@Override
								public void onClick( DialogInterface dialog,
										int which )
								{
									if ( mAgent.getDetail() != null )
									{
										String lResponse;
										if ( response == "1" )
											lResponse = getString( R.string.snmpHelper_badOid );
										else if ( response == "2" ) lResponse = getString( R.string.snmpHelper_badTargentSettings );
										else if ( response == "3" ) lResponse = getString( R.string.snmpHelper_timeout );
										else lResponse = response;
										mAgent.setDetail( mAgent
												.getDetail()
												.concat( "\n" )
												.concat(
														mSelectedOIDMeaning
																+ ": " )
												.concat( lResponse ) );
									}
									else
										mAgent.setDetail( mSelectedOIDMeaning
												+ ": " + response );
									mDetailField.setText( mAgent.getDetail() );
									mCallbacks.onAgentUpdated( mAgent );

								}
							} )
					.setNegativeButton( R.string.agent_dialog_no,
							new DialogInterface.OnClickListener()
							{

								@Override
								public void onClick( DialogInterface dialog,
										int which )
								{
									// don't do anything
								}
							} );

			AlertDialog dialog = builder.create();
			dialog.show();
		}
	}

}
